

#ifndef ERRO_H
#define ERRO_H


#include <QFile>
#include <QObject>


// Macros
#define ERR_ABORT(message) \
	Error::abort(__FILE__, __LINE__, message)

#define ERR_ASSERT(exp) \
	Error::assert(exp, #exp, __FILE__, __LINE__)

#define ERR_ASSERT_MESSAGE(exp, message) \
	Error::assert(exp, #exp, __FILE__, __LINE__, message)

#ifdef DEBUG
	#define TRY_CONNECT(sender, signal, receiver, member) \
		Error::connect(sender, #sender, signal, receiver, #receiver, member, __FILE__, __LINE__)

	#define TRY_DISCONNECT(sender, signal, receiver, member) \
		Error::disconnect(sender, #sender, signal, receiver, #receiver, member, __FILE__, __LINE__)
#else
	#define TRY_CONNECT QObject::connect
	#define TRY_DISCONNECT QObject::disconnect
#endif


/**
 * @brief	Singleton que fornece mecanismos para tratar de falhas. 
**/
class Error
{
public:

	/**
	 * @brief	Inicializa o sistema de log. Este deve ser executado na abertura da aplicação, e é
	 * 			responsável por abrir o arquivo de log e registrar os sinais de exceção do sistema. 
	**/
	static void initialize();

	/**
	 * @brief	Gera um evento de log. 
	 *
	 * @param	message	Mensagem que será registrada. 
	**/
	static void log(QString message);

	/**
	 * @brief	Define o sistema de log deve escrever no console.
	 *
	 * @param	TRUE caso a escrita esteja ativada. 
	**/
	static void setLogEchoEnabled(bool enabled) { m_logEchoEnabled = enabled; }

	/**
	 * @brief	Exibe um aviso de erro fatal, e aborta o programa. Esta função não deve ser chamada
	 * 			diretamente, a macro ERR_ABORT() deve ser usada em seu lugar. 
	 *
	 * @param	abortFilename	Resultado da macro __FILE__. 
	 * @param	abortFileLine	Resultado da macro __LINE__. 
	 * @param	message		Mensagem que será exibida. 
	**/
	static void abort(
		const char * abortFilename,
		unsigned int abortFileLine,
		QString message);

	/**
	 * @brief	Exibe um popup com a mensagem passada como prâmetro. 
	 *
	 * @param	message	Mensagem que será exibida. 
	**/
	static void warn(QString message);

	/**
	* @brief	Exibe um popup com a mensagem passada como prâmetro. 
	*
	* @param	message	Mensagem que será exibida. 
	**/
	static void info(QString message);

	/**
	 * @brief	Conecta um sinal a um slot verificando se teve sucesso. Esta função não deve ser
	 * 			chamada diretamente, a macro TRY_CONNECT() deve ser usada em seu lugar. 
	 *
	 * @param	sender				Objeto que irá gerar o sinal. 
	 * @param	senderAsString		Repreentação textual do sender. 
	 * @param	signal				Sinal a ser conectado. 
	 * @param	receiver			Objeto que irá receber o sinal. 
	 * @param	receiverAsString	Repreentação textual do receiver. 
	 * @param	slot				The slot. 
	 * @param	abortFileName		Resultado da macro __FILE__. 
	 * @param	abortFileline		Resultado da macro __LINE__. 
	**/
	static void connect(
		const QObject * sender,
		const char * senderAsString,
		const char * signal,
		const QObject * receiver,
		const char * receiverAsString,
		const char * slot,
		const char * abortFileName,
		unsigned int abortFileline);

	/**
	 * @brief	Desconecta um sinal a um slot verificando se teve sucesso. Esta função não deve ser
	 * 			chamada diretamente, a macro TRY_DISCONNECT() deve ser usada em seu lugar. 
	 *
	 * @param	sender				Objeto que irá gerar o sinal. 
	 * @param	senderAsString		Repreentação textual do sender. 
	 * @param	signal				Sinal a ser conectado. 
	 * @param	receiver			Objeto que irá receber o sinal. 
	 * @param	receiverAsString	Repreentação textual do receiver. 
	 * @param	slot				The slot. 
	 * @param	abortFileName		Resultado da macro __FILE__. 
	 * @param	abortFileline		Resultado da macro __LINE__. 
	**/
	static void disconnect(
		const QObject * sender,
		const char * senderAsString,
		const char * signal,
		const QObject * receiver,
		const char * receiverAsString,
		const char * slot,
		const char * abortFileName,
		unsigned int abortFileline);

	/**
	* @brief	Testa uma expressão booleana e aborta caso seja falsa. Esta função não deve ser chamada diretamente, a macro ERR_ASSERT() deve ser usada em seu lugar.
	 *
	 * @param	expression			Expressão a ser testada
	 * @param	expressionAsString	Representação textual da expressão testada. 
	 * @param	abortFilename		Resultado da macro __FILE__. 
	 * @param	abortFileLine		Resultado da macro __LINE__.
	 * @param	message				Mensagem que deve ser exibida caso aborte. 
	**/
#ifdef DEBUG
	static void assert(
		bool expression,
		const char * expressionAsString,
		const char * abortFilename,
		unsigned int abortFileLine,
		QString message = QString::null);
#else
	static void assert(
		bool,
		const char *,
		const char *,
		unsigned int,
		QString = QString::null) {}
#endif

private:

	/**
	 * @brief	Função que realmente aborta o programa levantando uma exceção AbortException.
	 *
	 * @param	abortFilename		Resultado da macro __FILE__. 
	 * @param	abortFileLine		Resultado da macro __LINE__.
	 * @param	additionalInfo		Informações adicionais da falha. 
	 *
	 * @see		AbortException
	**/
	static void abortPrivate(
		const char * abortFilename,
		unsigned int abortFileLine,
		const QString & additionalInfo);

	//! Decritor do arquivo de log. 
	static QFile m_logFile;

	//! Flag indicando se o log deve ser escrito no console. 
	static bool m_logEchoEnabled;
};

/**
 * @brief	Callback do qt utilizada para receber notificações do framework. 
 *
 * @param	type	Tipo da mensagem. 
 * @param	message		Mensagem. 
**/
void ERR_qtMessageOutput(
	QtMsgType type,
	const char * message);

/**
 * @brief	Retorna uma string contendo a stacktrace desta chamada
 *
 * @return	Stack trace na forma textual ou QString::null em caso de erro.
**/
QString getStackTrace(int stackDepth);
QString getStackTrace();

#endif // ERRO_H
